package jp.sourceforge.akjrcp.psp.imageconvert;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import jp.sourceforge.akjrcp.util.FileNameUtils;
import jp.sourceforge.akjrcp.util.image.ImageUtils;

public class ImageSplitter extends AbstractImageChanger{

private int overwrap=136;	//half
private int ignore=3;//for num mode





private int splitNum=4;
private int mode;
public static final int PIXEL_MODE=0;
public static final int NUMBER_MODE=1;
private boolean supportDoubleSize;
private int doubleSizeLimit=1300;

public ImageSplitter(){
	time=System.currentTimeMillis();
}








public void changeImage(String imageFileName,InputStream imageInput,File exportDir) throws IOException{
	if(cancel){
		return;
	}
	int thisWidth;
	int thisHeight;
	BufferedImage baseImage=imageLoader.loadImage(imageFileName,imageInput);
	//log.info("load:"+Runtime.getRuntime().freeMemory()/1000);
	if(baseImage==null){
		//log.info("invalid-image:"+imageFileName);
		//show log
		return;
	}
	if(supportDoubleSize && baseImage.getWidth()>doubleSizeLimit){
		thisWidth=width*2;
		thisHeight=height*2;
	}else{
		thisWidth=width;
		thisHeight=height;
	}
	//writePng(baseImage,99,imageFile,exportDir);//for debug
	double ratio=1.0;
	//if(baseImage.getWidth()>width){
		ratio=(double)thisWidth/baseImage.getWidth();
	//}
	int resizedImageHeight=(int) (baseImage.getHeight()*ratio);
	BufferedImage resizedImage=baseImage;//for 1.0
	if(ratio!=1.0){
		BufferedImage rgb=toRGB(baseImage);
		baseImage.getGraphics().dispose();
		baseImage=null;
		System.gc();
		resizedImage=resize(rgb,thisWidth,resizedImageHeight);
		rgb.getGraphics().dispose();
		rgb=null;
		System.gc();
	}
	//saveImage(resizedImage,0,imageFileName,exportDir);//for debug
	
	
	
	if(resizedImageHeight-ignore<=thisHeight){
		//one image;
		//TODO
	
		saveImage(toRGB(resizedImage),1,imageFileName,exportDir);
	}else{
		if(mode==PIXEL_MODE){
			splitImage(imageFileName,exportDir,resizedImage,resizedImageHeight,overwrap,thisWidth,thisHeight);
		}else{//NUM_MODE
			//log.infonum mode:"+splitNum);
			int mod=thisHeight*splitNum-resizedImageHeight;
		//	log.infomod:"+mod);
			if(mod<=0){	//split num is small,auto set
				
				int minSplit=resizedImageHeight/thisHeight;
				if(resizedImageHeight%thisHeight>0){
					minSplit++;
					}
				int m=thisHeight*minSplit-resizedImageHeight;
				double ov=0;
				if(m>0)
					ov=(double)m/(minSplit-1); //final image has no wrap
			//	log.infomin:"+minSplit+",ov:"+ov);
				splitImage(imageFileName,exportDir,resizedImage,resizedImageHeight,ov,thisWidth,thisHeight);
			}else{//split same size
				double ov=(double)mod/(splitNum-1);
				if(thisHeight==height*2){//double mode
					int num=splitNum;
					while(ov>thisHeight/2){//max overwrap is 50%;
						int m=thisHeight*num-resizedImageHeight;
						ov=(double)m/(num-1);
						num--;
						if(num==1){
							break;
						}
					}
				splitImage(imageFileName,exportDir,resizedImage,resizedImageHeight,ov,thisWidth,thisHeight);
				}else{
				
				splitImage(imageFileName,exportDir,resizedImage,resizedImageHeight,ov,thisWidth,thisHeight);
				}
			}
		}
		//dispose
		resizedImage.getGraphics().dispose();
		System.gc();
	}
	
}

public  void splitImage(String imageFileName,File exportDir,BufferedImage resizedImage,int imageHeight,double wrapValue,int thisWidth,int thisHeight) throws IOException{
	int index=1;
	double current=0;
	while(current<imageHeight){
		if(cancel){
			return;
		}
		if(current+wrapValue>imageHeight-ignore){
			break;//if h is smaller than ignore,never write
		}
		BufferedImage clipImage=new BufferedImage(thisWidth,thisHeight,BufferedImage.TYPE_INT_RGB);
		clipImage.getGraphics().drawImage(resizedImage,0,0,thisWidth,thisHeight,0,(int)current,thisWidth,(int)(thisHeight+current),null);
		saveImage(clipImage,index,imageFileName,exportDir);
		current+=thisHeight-wrapValue;
		index++;
		clipImage=null;
	}
}

//this based persent mode.
/*
public int countSplitImage(File imageFile) throws IOException{
	BufferedImage baseImage=loadImage(imageFile);
	double ratio=1.0;
	if(baseImage.getWidth()>width){
		ratio=(double)width/baseImage.getWidth();
	}
	int h=(int) (baseImage.getHeight()*ratio);
	
	if(h-ignore<=height){
		return 1;
	}else{
		int index=1;
		int current=0;
		while(current<h){
			if(current+overwrap>h-ignore){
				break;//if h is smaller than ignore,never write
			}
			current+=height-overwrap;
			index++;
		}
		return index-1;
	}
}*/











//grey scale image got a problem
public static BufferedImage resize(BufferedImage baseImage, int width, int height) {
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    /*
    double sx = (double)width / (double)baseImage.getWidth();
    double sy = (double)height / (double)baseImage.getHeight();
    AffineTransform trans = AffineTransform.getScaleInstance(sx, sy);
 
 
    
    AffineTransformOp operation = new AffineTransformOp(trans, 
       AffineTransformOp.TYPE_BILINEAR);
    //		 AffineTransformOp.TYPE_BICUBIC);
	 
    //this need too much memory?
    operation.filter(baseImage, image);
    */
    Graphics2D g2=(Graphics2D) image.getGraphics();
    g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
	g2.drawImage(baseImage, 0, 0, width, height,0, 0, baseImage.getWidth(), baseImage.getHeight(),  null);
    return image;
}

public int getOverwrap() {
	return overwrap;
}

public void setOverwrap(int overwrap) {
	this.overwrap = overwrap;
}





public int getMode() {
	return mode;
}

public void setMode(int mode) {
	this.mode = mode;
}

public boolean isSupportDoubleSize() {
	return supportDoubleSize;
}

public void setSupportDoubleSize(boolean supportDoubleSize) {
	this.supportDoubleSize = supportDoubleSize;
}

public int getSplitNum() {
	return splitNum;
}

public void setSplitNum(int splitNum) {
	this.splitNum = splitNum;
}








public int getDoubleSizeLimit() {
	return doubleSizeLimit;
}








public void setDoubleSizeLimit(int doubleSizeLimit) {
	this.doubleSizeLimit = doubleSizeLimit;
}

}
